---
title: "Get started with Sequin Stream"
sidebarTitle: "Sequin Stream"
description: "Build exactly-once processing pipelines for Postgres changes without additional infrastructure. Learn about Sequin's native stream with an HTTP interface."
---

import QuickstartInitialSteps from '/snippets/quickstart-initial-steps.mdx';
import QuickstartSourceStep from '/snippets/quickstart-source-step.mdx';
import QuickstartBackfillStep from '/snippets/quickstart-backfill-step.mdx';

In this quickstart, you'll create a real-time data pipeline that streams changes from a Postgres database to a [Sequin Stream](/reference/sinks/sequin-stream). Sequin Stream is a Postgres-based message stream, native to Sequin.

You'll:

- Boot Sequin
- Connect to a sample playground database
- Create a Sequin Stream to receive database changes
- See your changes flow in real-time

By the end, you'll have hands-on experience setting up Postgres change data capture (CDC) with Sequin and Sequin Stream.

<Tip>
  This is the quickstart for streaming Postgres to Sequin Stream. See the [how-to guide](/how-to/stream-postgres-to-sequin-stream) for an explanation of how to use the Sequin Stream sink or the [reference](/reference/sinks/sequin-stream) for details on all configuration options.
</Tip>

<Steps titleSize="h2">
 <QuickstartInitialSteps />
 <Step title="Create a Sequin Stream Sink" icon="wifi">
  With the playground database connected, you can create a [sink](/reference/sinks/overview). This sink will send changes to the `products` table to a Sequin Stream:

  <Steps>
    <Step title="Navigate to Sinks">
      Click "Sinks" in the sidebar navigation, then click "Create Sink".
    </Step>

    <Step title="Select sink type">
      Select "Sequin Stream" as the sink type and click "Continue".
    </Step>

    <QuickstartSourceStep />
    <QuickstartBackfillStep />

    <Step title="Create the sink">
      You can leave the rest of the defaults. As configured, the Sequin Stream will first receive a backfill of all rows currently in the `products` table. Then, it will receive all changes to the `products` table in real-time.

      Click "Create Sink" to finish setting up your Sequin Stream.
    </Step>
  </Steps>
 </Step>

  <Step title="See changes flow to your Sequin Stream" icon="waveform-lines">
    On the new sink's overview page, you should see the "Health" status turn green, indicating data is flowing to your stream.

    Let's confirm messages are flowing:

    <Steps>
    <Step title="Messages tab">
      Click the "Messages" tab. You'll see a bunch of messages are available, pending delivery:

      <Frame>
        <img style={{ maxWidth: '700px' }} src="/images/quickstart/sequin-stream/messages-tab.png" alt="List of recently delivered messages" />
      </Frame>

      <Check>
        Sequin indicates it backfilled the `products` table to your stream.
      </Check>
    </Step>
      <Step title="Receive messages">
        Using the Sequin Stream API, let's receive some messages. Copy the curl command from the "Overview" tab:

        <Frame>
          <img style={{ maxWidth: '700px' }} src="/images/quickstart/sequin-stream/curl-command.png" alt="Curl command to receive messages" />
        </Frame>

        In your terminal, run the `curl` command. You'll receive a response with a single message from the initial backfill of the `products` table:

        ```json
        {
          "data": [
            {
              "ack_id": "MTYyeJ7abUjl1pO",
              "record": {
                "id": 1,
                "name": "Avocados (3 pack)",
                "price": 6.99
              },
              "action": "read",
              "metadata": {
                "table_schema": "public",
                "table_name": "products",
                "commit_timestamp": "2024-03-20T15:30:00Z",
                "commit_lsn": 123456789,
                "commit_idx": 1,
                "database_name": "myapp-prod",
                "consumer": {
                  "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
                  "name": "products-stream",
                  "annotations": {}
                },
                "database": {
                  "id": "12345678-9abc-def0-1234-56789abcdef0",
                  "name": "myapp-prod",
                  "annotations": {},
                  "database": "myapp-prod",
                  "hostname": "db.example.com"
                }
              }
            }
          ]
        }
        ```

        If you run the `curl` command again, you'll receive a different message. That's because Sequin Stream only re-delivers messages after the visibility timeout expires.

        <Check>
          Messages are flowing from Sequin to your stream.
        </Check>
      </Step>

      <Step title="Make some changes">
        Let's make some changes to the `products` table and see them flow to your stream.

        In your terminal, run the following command to insert a new row into the `products` table:

        ```bash
        docker exec -i sequin-sequin_postgres-1 \
          psql -U postgres -d sequin_playground -c \
          "insert into products (name, price) values ('Organic Honey (16 oz)', 12.99);"
        ```

        Receive messages from your stream again to see the new change. This time, include the `?batch_size=10` parameter to receive multiple messages at once, like so:

        ```bash
        curl -X GET "http://localhost:7376/api/http_pull_consumers/products_sink/receive?batch_size=10" \
          -H "Authorization: Bearer YOUR_API_TOKEN"
        ```

        Feel free to try other changes:

        <AccordionGroup>
          <Accordion title="Update a product's price">
            ```bash
            docker exec -i sequin-sequin_postgres-1 \
              psql -U postgres -d sequin_playground -c \
              "update products set price = 7.99 where name = 'Avocados (3 pack)';"
            ```
          </Accordion>

          <Accordion title="Change a product's name">
            ```bash
            docker exec -i sequin-sequin_postgres-1 \
              psql -U postgres -d sequin_playground -c \
              "update products set name = 'Organic Avocados (3 pack)' where name = 'Avocados (3 pack)';"
            ```
          </Accordion>

          <Accordion title="Delete a product">
            ```bash
            docker exec -i sequin-sequin_postgres-1 \
              psql -U postgres -d sequin_playground -c \
              "delete from products where name = 'Blueberries (6 oz)';"
            ```
          </Accordion>
        </AccordionGroup>

        Each change will appear in your stream within a few seconds.

        You can acknowledge messages to ensure they're not delivered again:

        ```bash
        curl -X POST "http://localhost:7376/api/http_pull_consumers/products_sink/ack" \
          -H "Authorization: Bearer YOUR_API_TOKEN" \
          -H "Content-Type: application/json" \
          -d '{"ack_ids": ["MTYyeJ7abUjl1pO"]}'
        ```
      </Step>
    </Steps>
  </Step>
</Steps>

<Check>
  Great work!
</Check>

You've successfully:

- Set up a complete Postgres change data capture pipeline
- Loaded existing data through a backfill
- Made changes to the `products` table
- Verified changes are flowing to your Sequin Stream

## Ready to stream

Now you're ready to connect your own database to Sequin and start streaming changes:

<CardGroup cols={2}>
  <Card title="Guide: Connect Postgres" icon="elephant" href="/connect-postgres">
    Connect your Postgres database to Sequin.
  </Card>
  <Card title="Guide: Setting up a Sequin Stream sink" icon="stream" href="/how-to/stream-postgres-to-sequin-stream">
    Setup a Sequin Stream sink to process changes with exactly-once delivery.
  </Card>
</CardGroup>
